package cn.snmp.mutual.org.opennms.protocols.ip;

public class OC16ChecksumProducer {
    private int m_cksum;
    private boolean m_finalized;

    private static int byteToInt(final byte b) {
        if (b < 0) {
            return b + 256;
        }
        return b;
    }

    private static int shortToInt(final short s) {
        if (s < 0) {
            return s + 65536;
        }
        return s;
    }

    private void finalizeSum() {
        if ((this.m_cksum & 0xFFFF0000) != 0x0) {
            this.m_cksum = (this.m_cksum >> 16 & 0xFFFF) + (this.m_cksum & 0xFFFF);
            this.m_cksum += this.m_cksum >>> 16;
        }
        this.m_finalized = true;
    }

    public OC16ChecksumProducer() {
        this.m_cksum = 0;
        this.m_finalized = false;
    }

    public void add(final byte b) {
        this.add(b, (byte) 0);
    }

    public void add(final byte a, final byte b) {
        this.m_cksum += (byteToInt(a) << 8 | byteToInt(b));
        this.m_finalized = false;
    }

    public void add(final short s) {
        this.m_cksum += shortToInt(s);
        this.m_finalized = false;
    }

    public void add(final int i) {
        this.m_cksum += (i >> 16 & 0xFFFF);
        this.m_cksum += (i & 0xFFFF);
        this.m_finalized = false;
    }

    public void add(final long l) {
        this.m_cksum += ((int) (l >> 48) & 0xFFFF);
        this.m_cksum += ((int) (l >> 32) & 0xFFFF);
        this.m_cksum += ((int) (l >> 16) & 0xFFFF);
        this.m_cksum += ((int) l & 0xFFFF);
        this.m_finalized = false;
    }

    public void reset() {
        this.m_cksum = 0;
        this.m_finalized = false;
    }

    public short getChecksum() {
        if (!this.m_finalized) {
            this.finalizeSum();
        }
        return (short) (~this.m_cksum & 0xFFFF);
    }
}
